在 Python 中若要撰寫多執行緒(multithreading)的平行化程式,最基本的方式是使用 threading 這個模組來建立子執行緒。
模組 :
import threading
# 子執行緒的工作函數
def job():
for i in range(5):
print("Child thread:", i)
time.sleep(1)
t = threading.Thread(target = job)
t.start()
大概就是一個多 client 端即時通訊系統,server 端處理連接並管理 client 端消息,而每個 cleint 端獨立接收和發送消息
伺服器端:
客戶端:
import socket
from threading import Thread
import uuid # 用於生成唯一標識符
host = ''
port = 8808
socket_server = None # 負責監聽的 socket
conn_pool = {} # 連接池,使用字典來存放每個客戶端的標記和 socket 對象
# 初始化伺服器端
def init():
global socket_server
# 創建 socket 對象
socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_server.bind((host, port)) # 綁定地址
socket_server.listen(5) # 設置最大等待連接數
print("Listening...")
# 接收新連接
def accept_client():
while True:
client, _ = socket_server.accept() # 阻塞,等待客戶端連接
# 請求客戶端發送名稱
name = client.recv(1024).decode(encoding='utf8')
# 生成唯一標識符
client_id = str(uuid.uuid4())
# 使用名稱和標識符存儲客戶端
if name not in conn_pool:
conn_pool[name] = {'id': client_id, 'socket': client}
print(f'客戶端 {name} 已連接,ID: {client_id}')
# 請求客戶端確認連接
client.sendall("連接伺服器成功!".encode(encoding='utf8'))
# 為每個客戶端創建一個獨立的線程進行管理
thread = Thread(target=message_handle, args=(client, name))
thread.daemon = True # 設置為 daemon thread
thread.start()
else:
client.sendall("名稱已被使用,請重新連接。".encode(encoding='utf8'))
client.close()
# 訊息處理
def message_handle(client, name):
while True:
try:
message = client.recv(1024)
if len(message) == 0:
break
print(f"客戶端 {name} 消息:", message.decode(encoding='utf8'))
except socket.error as e:
print(f"\n接收消息錯誤:{e}")
break
client.close()
if name in conn_pool:
del conn_pool[name] # 使用名稱刪除連接
print(f"客戶端 {name} 下線了。")
if __name__ == '__main__':
init()
# 新開一個線程,用於接收新連接
thread = Thread(target=accept_client)
thread.daemon = True
thread.start()
while True:
cmd = input("""
--------------------------
選擇操作:
1. 查看當前在線人數
2. 給指定客戶端發送消息
3. 關閉伺服器端
--------------------------
請輸入選擇 (1/2/3):
""")
if cmd == '1':
print("~~~~~~~~~~~~~~~~~~~~~~~~~~")
# 連接池的長度就是連接人數
print("當前在線人數:", len(conn_pool))
elif cmd == '2':
print("~~~~~~~~~~~~~~~~~~~~~~~~~~")
# 列出所有客戶端名稱
print("當前在線客戶端名稱:", list(conn_pool.keys()))
# name 是指定要傳送給哪個 Client 的名稱,msg 就是要傳送的訊息
input_data = input("請輸入“客戶端名稱,訊息”的形式:")
if ',' in input_data:
name, msg = input_data.split(",", 1)
if name in conn_pool:
conn_pool[name]['socket'].sendall(msg.encode(encoding='utf8'))
else:
print("無效的客戶端名稱。")
else:
print("請按照“客戶端名稱,訊息”的形式輸入。")
elif cmd == '3':
socket_server.close() # 關閉伺服器端
break
import socket
import threading
# 接收來自伺服器的消息並打印出來
def receive_messages(sock):
while True:
try:
response = sock.recv(1024).decode('utf8')
if response:
print("\n伺服器回應:", response)
else:
# 如果沒有數據,伺服器可能已關閉連接
print("\n伺服器已關閉連接")
break
except socket.error as e:
print(f"\n接收消息錯誤:{e}")
break
def main():
# 創建 socket 對象並連接到伺服器
socket_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_client.connect(('127.0.0.1', 8808))
try:
# 輸入並發送名稱
name = input("請輸入您的名稱:")
socket_client.send(name.encode(encoding='utf8'))
# 接收並打印連接成功消息
print(socket_client.recv(1024).decode(encoding='utf8'))
# 創建線程來接收伺服器的消息
recv_thread = threading.Thread(target=receive_messages, args=(socket_client,))
recv_thread.daemon = True
recv_thread.start()
while True:
# 發送消息
msg = input("發送消息 (輸入 'exit' 退出):")
if msg.lower() == 'exit':
socket_client.send("exit".encode('utf8')) # 通知伺服器客戶端將要退出
break
socket_client.send(msg.encode('utf8'))
except Exception as e:
print(f"發生錯誤:{e}")
finally:
# 確保在退出時關閉連接
socket_client.close()
if __name__ == "__main__":
main()
參考資料 :
https://blog.csdn.net/qq_39687901/article/details/81531101
https://blog.gtwang.org/programming/python-threading-multithreaded-programming-tutorial/